#ifndef __HxMD5H__
#define __HxMD5H__

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

using namespace std;

#ifndef MD5EX_CRCBIN_LEN
   #define MD5EX_CRCBIN_LEN 16
   #define MD5EX_CRCSTR_LEN 32
#endif


#ifndef uint32
   #ifdef __alpha
      typedef unsigned int uint32;
   #else
      typedef unsigned int uint32;
   #endif
#endif

class MD5_CTX {
public:
	MD5_CTX();
	virtual ~MD5_CTX();

	void update(const char *value, unsigned len);
	void final(unsigned char digest[16]);

	uint32 state[4];
	uint32 count[2];
	unsigned char in[64];
};


/* The four core functions - F1 is optimized somewhat */

//#define F1(x, y, z) (x & y | ~x & z)
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))

/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )


namespace HxMD5 {
	void md5(const string& what, string& md5 );
	void MD5Transform(uint32 buf[4], uint32 in[16]);
	void CRCToString(unsigned char pcCrc[MD5EX_CRCSTR_LEN], string& dest);
}

#endif
